package stupidMineralCollector.model;

import jnibwapi.BWAPIEventListener;
import jnibwapi.JNIBWAPI;
import jnibwapi.model.Unit;
import jnibwapi.types.UnitType;

import java.util.HashSet;

import stupidMineralCollector.Constants;

/**
 * Created by rudolpst on 17.02.14.
 */
public class StupidMineralCollector implements BWAPIEventListener, Runnable {

	private final JNIBWAPI bwapi;

	private HashSet<SCV> SCVs;

	private HashSet<CommandCenter> commandCenters;

	private HashSet<Unit> mineralFields;

	private PheromoneMap pheromoneMap;

	private int frame;

	private boolean gameRunning;

	public StupidMineralCollector() {
		System.out.println("This is the stupidMineralCollector :)");

		gameRunning = false;

		bwapi = new JNIBWAPI(this, false);

	}

	@Override
	public void matchStart() {
		System.out.println("Game Started");

		frame = 0;
		pheromoneMap = new PheromoneMap(bwapi.getMap().getWidth(), bwapi.getMap().getHeight());

		SCVs = new HashSet<>();
		commandCenters = new HashSet<>();
		mineralFields = new HashSet<>();

		bwapi.enableUserInput();
		bwapi.setGameSpeed(0);

		gameRunning = true;
	}

	@Override
	public void matchFrame() {
		if (frame % 2 == 0) {
			synchronized(SCVs)
			{
				try
				{
					for (SCV scv : SCVs) {
						scv.step();
					}
				}
				catch(Exception ex)
				{
					System.out.println(ex.getMessage());
				}
			}
			synchronized(commandCenters)
			{
				for (CommandCenter cc : commandCenters) {
					cc.step();
				}
			}

			pheromoneMap.diffuseAndEvaporatePheromones();

		}
		if (frame % 1000 == 0) {
			System.out.println("Frame: " + frame);
		}
		frame++;
	}

	@Override
	public void unitDiscover(int unitID) {
		Unit unit = bwapi.getUnit(unitID);
		int typeID = unit.getTypeID();

		if (typeID == UnitType.UnitTypes.Terran_SCV.getID()) {
			synchronized (SCVs) {
				SCVs.add(new SCV(unit, bwapi, mineralFields, pheromoneMap));
			}
		} else if (typeID == UnitType.UnitTypes.Terran_Command_Center.getID()) {
			synchronized (commandCenters) {
				commandCenters.add(new CommandCenter(unit, bwapi));
			}
		} else if (typeID == UnitType.UnitTypes.Resource_Mineral_Field.getID()) {
			synchronized (mineralFields) {
				mineralFields.add(unit);
			}
		}
	}

	@Override
	public void unitDestroy(int unitID) {
		synchronized (SCVs) {
			SCV rm = null;
			for (SCV scv : SCVs) {
				if (scv.getID() == unitID) {
					rm = scv;
					break;
				}
			}
			if( rm != null )
			{
				SCVs.remove(rm);
				return;
			}
		}

		synchronized (mineralFields) {
			Unit rmMineralField = null;
			for (Unit min : mineralFields) {
				if (min.getID() == unitID) {
					rmMineralField = min;
					break;
				}
			}
			if( rmMineralField != null )
			{
				mineralFields.remove(rmMineralField);
				return;
			}
		}
	}

	@Override
	public void connected() {
		System.out.println("Connected");
	}

	@Override
	public void matchEnd(boolean winner) {
		gameRunning = false;
	}

	@Override
	public void keyPressed(int keyCode) {

	}

	@Override
	public void sendText(String text) {

	}

	@Override
	public void receiveText(String text) {

	}

	@Override
	public void playerLeft(int playerID) {

	}

	@Override
	public void nukeDetect(int x, int y) {

	}

	@Override
	public void nukeDetect() {

	}

	@Override
	public void unitEvade(int unitID) {

	}

	@Override
	public void unitShow(int unitID) {

	}

	@Override
	public void unitHide(int unitID) {

	}

	@Override
	public void unitCreate(int unitID) {
	}

	@Override
	public void unitMorph(int unitID) {

	}

	@Override
	public void unitRenegade(int unitID) {

	}

	@Override
	public void saveGame(String gameName) {

	}

	@Override
	public void unitComplete(int unitID) {

	}

	@Override
	public void playerDropped(int playerID) {

	}

	@Override
	public void run() {
		bwapi.start();
	}

	public PheromoneMap getPheromoneMap() {
		return pheromoneMap;
	}

	public boolean isGameRunning() {
		return gameRunning;
	}

	public Object[] getSCVs() {
		Object[] result;
		synchronized(SCVs)
		{
			result = this.SCVs.toArray();
		}
		return result;
	}

	public Object[] getMinerals() {
		Object[] result;
		synchronized(mineralFields)
		{
			result = this.mineralFields.toArray();
		}
		return result;
	}
}
